package __4_0

/*
#cgo CFLAGS: -I./include
#cgo LDFLAGS: -L${SRCDIR}/lib -larcsoft_face_engine
#include <stdlib.h>
#include "./include/merror.h"
#include "./include/asvloffscreen.h"
#include "./include/arcsoft_face_sdk.h"
*/
import "C"

import (
	"encoding/json"
	"unsafe"
)

// 引擎结构体
type FaceEngine struct {
	handle C.MHandle
}

// 多人脸信息结构体
type MultiFaceInfo struct {
	FaceRect         []Rect               // 人脸框信息
	FaceOrient       []int32              // 输入图像的角度
	FaceNum          int32                // 检测到的人脸个数
	FaceID           []int32              // face ID，IMAGE模式下不返回FaceID
	FaceDataInfoList []C.ASF_FaceDataInfo // 多张人脸信息
	native           *C.ASF_MultiFaceInfo
	WearGlasses      []float32 // 带眼镜置信度[0-1]，推荐阈值0.5
	LeftEyeClosed    []int32   // 左眼状态 0 未闭眼 1 闭眼
	RightEyeClosed   []int32   // 右眼状态 0 未闭眼 1 闭眼
}

// 人脸坐标结构体
type Rect struct {
	Left   int32
	Top    int32
	Right  int32
	Bottom int32
}

// 活体置信度结构体
type LivenessThreshold struct {
	ThresholdModelBGR float32
	ThresholdModelIR  float32
}

// 激活文件信息结构体
type ActiveFileInfo struct {
	StartTime   string //开始时间
	EndTime     string //截止时间
	Platform    string //平台
	SdkType     string //sdk类型
	AppId       string //APPID
	SdkKey      string //SDKKEY
	SdkVersion  string //SDK版本号
	FileVersion string //激活文件版本号
}

// 版本信息结构体
type Version struct {
	Version   string // 版本号
	BuildDate string // 构建日期
	CopyRight string // Copyright
}

// 单人脸信息结构体
type SingleFaceInfo struct {
	FaceRect   Rect               // 人脸框信息
	FaceOrient int32              // 输入图像的角度，可以参考 ArcFaceCompare_OrientCode
	DataInfo   C.ASF_FaceDataInfo // 单张人脸信息
}

// 人脸信息
type FaceDataInfo struct {
	Data     C.MPVoid // 人脸信息
	DataSize int32    //人脸信息长度
}

// 人脸特征结构体
type FaceFeature struct {
	Feature     []byte // 人脸特征信息
	FeatureSize int32  // 人脸特征信息长度
	native      *C.ASF_FaceFeature
	featurePtr  *C.MByte
}

// 年龄信息结构体
type AgeInfo struct {
	AgeArray []int32 // "0" 代表不确定，大于0的数值代表检测出来的年龄结果
	Num      int32   // 检测的人脸个数
}

// 性别信息结构体
type GenderInfo struct {
	GenderArray []int32 // "0" 表示 男性, "1" 表示 女性, "-1" 表示不确定
	Num         int32   // 检测的人脸个数
}

// 人脸3D角度信息结构体
type Face3DAngle struct {
	Roll   []float32
	Yaw    []float32
	Pitch  []float32
	Status []int32 // 0: 正常，其他数值：出错
	Num    int32
}

// 活体信息
type LivenessInfo struct {
	IsLive []int32 // 0:非真人 1:真人 -1:不确定 -2:传入人脸数>1
	Num    int32
}

// 口罩检测信息
type MaskInfo struct {
	MaskArray []int32 // 0" 代表没有带口罩，"1"代表带口罩 ,"-1"表不确定
	Num       int32
}

// 坐标
type FaceLandMark struct {
	X float32
	Y float32
}

// 额头点位信息
type LandMarkInfo struct {
	Point []FaceLandMark //额头点位
	Num   int32          //人脸数量
}

// 设备信息
type DeviceInfo struct {
	DeviceInfo string
}

// SDK错误码
type EngineError struct {
	Code int
	Text string
}

const (
	DetectModeVideo       = C.ASF_DETECT_MODE_VIDEO
	DetectModeImage       = C.ASF_DETECT_MODE_IMAGE
	OrientPriority0       = C.ASF_OP_0_ONLY
	OrientPriority90      = C.ASF_OP_90_ONLY
	OrientPriority270     = C.ASF_OP_270_ONLY
	OrientPriority180     = C.ASF_OP_180_ONLY
	OrientPriorityAllOut  = C.ASF_OP_ALL_OUT
	EnableNone            = C.ASF_NONE
	EnableFaceDetect      = C.ASF_FACE_DETECT
	EnableFaceRecognition = C.ASF_FACERECOGNITION

	EnableAge         = C.ASF_AGE
	EnableGender      = C.ASF_GENDER
	EnableFace3DAngle = C.ASF_FACE3DANGLE
	EnableLiveness    = C.ASF_LIVENESS
	EnableIRLiveness  = C.ASF_IR_LIVENESS

	ColorFormatBGR24 = C.ASVL_PAF_RGB24_B8G8R8
	ColorFormatNV12  = C.ASVL_PAF_NV12
	ColorFormatNV21  = C.ASVL_PAF_NV21
	ColorFormatI420  = C.ASVL_PAF_I420
	ColorFormatYUYV  = C.ASVL_PAF_YUYV

	EnableFaceShelter    = C.ASF_FACESHELTER     //开启人脸遮挡检测
	EnableMaskDetect     = C.ASF_MASKDETECT      //开启口罩检测
	EnableUpdateFaceData = C.ASF_UPDATE_FACEDATA //开启人脸信息检测
	EnableImageQuality   = C.ASF_IMAGEQUALITY    //开启图像质量检测
	EnableFaceLandMark   = C.ASF_FACELANDMARK    //开启人脸特征点检测

	ASFRecognition = C.ASF_RECOGNITION //用于识别照人脸特征提取
	ASFRegister    = C.ASF_REGISTER    //用于注册照人脸特征提取
	ASFLifePhoto   = C.ASF_LIFE_PHOTO  //用于生活照之间的特征比对，推荐阈值0.80
	ASFIdPhoto     = C.ASF_ID_PHOTO    //用于证件照或生活照与证件照之间的特征比对，推荐阈值0.82
)

// 创建一个新的引擎实例
//
// 如果调用初始化函数失败则返回一个错误
func NewFaceEngine(detectMode, detectFaceOrientPriority uint32, maxFaceNum, combinedMask C.MInt32) (*FaceEngine, error) {
	engine, err := &FaceEngine{}, error(nil)
	r := C.ASFInitEngine(
		detectMode,
		detectFaceOrientPriority,
		maxFaceNum,
		combinedMask,
		(*C.MHandle)(unsafe.Pointer(&engine.handle)),
	)
	if r != C.MOK {
		err = newError(int(r), "初始化引擎失败")
	}
	return engine, err
}

// 获取激活文件信息接口
func GetActiveFileInfo() (ActiveFileInfo, error) {
	asfActiveFileInfo := &C.ASF_ActiveFileInfo{}
	r := C.ASFGetActiveFileInfo(asfActiveFileInfo)
	if r != C.MOK {
		return ActiveFileInfo{}, newError(int(r), "获取激活文件信息失败")
	}
	info := ActiveFileInfo{
		StartTime:   C.GoString(asfActiveFileInfo.startTime),
		EndTime:     C.GoString(asfActiveFileInfo.endTime),
		Platform:    C.GoString(asfActiveFileInfo.platform),
		SdkType:     C.GoString(asfActiveFileInfo.sdkType),
		AppId:       C.GoString(asfActiveFileInfo.appId),
		SdkKey:      C.GoString(asfActiveFileInfo.sdkKey),
		SdkVersion:  C.GoString(asfActiveFileInfo.sdkVersion),
		FileVersion: C.GoString(asfActiveFileInfo.fileVersion),
	}
	return info, nil
}

// 获取设备信息接口 采集当前设备信息（可离线）
func GetActiveDeviceInfo() ([]byte, error) {
	deviceInfo := C.CString("")
	defer C.free(unsafe.Pointer(deviceInfo))
	r := C.ASFGetActiveDeviceInfo((*C.MPChar)(unsafe.Pointer(&deviceInfo)))
	if r != C.MOK {
		return nil, newError(int(r), "采集当前设备信息失败")
	}
	str := C.GoString(deviceInfo)
	b := make([]byte, len(str))
	copy(b, str)
	return b, nil
}

// 在线激活接口
func OnlineActivationPro(appId, sdkKey, activeKey string) (err error) {
	id := C.CString(appId)
	key := C.CString(sdkKey)
	active := C.CString(string(activeKey))
	defer func() {
		C.free(unsafe.Pointer(id))
		C.free(unsafe.Pointer(key))
		C.free(unsafe.Pointer(active))
	}()
	r := C.ASFOnlineActivation(id, key, active)
	if r != C.MOK && r != C.MERR_ASF_ALREADY_ACTIVATED {
		err = newError(int(r), "激活SDK失败")
	}
	return
}

// 离线激活接口
func OfflineActivationPro(filePath string) (err error) {

	path := C.CString(filePath)
	defer func() {
		C.free(unsafe.Pointer(path))
	}()
	r := C.ASFOfflineActivation(path)
	if r != C.MOK && r != C.MERR_ASF_ALREADY_ACTIVATED {
		err = newError(int(r), "离线激活SDK失败")
	}
	return
}

// 传入修改后的人脸框，更新人脸信息，用于做双目对齐或其他策略
func (engine *FaceEngine) UpdateFaceDataPro(width, height int, format C.MInt32, imgData []byte) (faceInfo MultiFaceInfo, err error) {
	asfFaceInfo := &C.ASF_MultiFaceInfo{}
	r := C.ASFUpdateFaceData(engine.handle,
		C.MInt32(width),
		C.MInt32(height),
		format,
		(*C.MUInt8)(unsafe.Pointer(&imgData[0])),
		asfFaceInfo,
	)
	if r != C.MOK {
		return faceInfo, newError(int(r), "更新人脸信息失败")
	}
	faceNum := int32(asfFaceInfo.faceNum)
	faceInfo.FaceRect = (*[10]Rect)(unsafe.Pointer(asfFaceInfo.faceRect))[:faceNum:faceNum]
	faceInfo.FaceOrient = (*[10]int32)(unsafe.Pointer(asfFaceInfo.faceOrient))[:faceNum:faceNum]
	if asfFaceInfo.faceID != nil {
		faceInfo.FaceID = (*[10]int32)(unsafe.Pointer(asfFaceInfo.faceID))[:faceNum:faceNum]
	}
	// 新增参数 人脸信息
	faceInfo.FaceDataInfoList = (*[10]C.ASF_FaceDataInfo)(unsafe.Pointer(asfFaceInfo.faceDataInfoList))[:faceNum:faceNum]
	faceInfo.WearGlasses = (*[10]float32)(unsafe.Pointer(asfFaceInfo.wearGlasses))[:faceNum:faceNum]
	faceInfo.LeftEyeClosed = (*[10]int32)(unsafe.Pointer(asfFaceInfo.leftEyeClosed))[:faceNum:faceNum]
	faceInfo.RightEyeClosed = (*[10]int32)(unsafe.Pointer(asfFaceInfo.rightEyeClosed))[:faceNum:faceNum]

	faceInfo.FaceNum = faceNum
	faceInfo.native = asfFaceInfo

	return
}

// 人脸检测，目前不支持IR图像数据检测
func (engine *FaceEngine) DetectFacesPro(width, height int, format C.MInt32, imgData []byte) (faceInfo MultiFaceInfo, err error) {
	asfFaceInfo := &C.ASF_MultiFaceInfo{}
	r := C.ASFDetectFaces(engine.handle,
		C.MInt32(width),
		C.MInt32(height),
		format,
		(*C.MUInt8)(unsafe.Pointer(&imgData[0])),
		asfFaceInfo,
		C.ASF_DETECT_MODEL_RGB,
	)
	if r != C.MOK {
		return faceInfo, newError(int(r), "人脸检测失败")
	}
	faceNum := int32(asfFaceInfo.faceNum)
	faceInfo.FaceRect = (*[10]Rect)(unsafe.Pointer(asfFaceInfo.faceRect))[:faceNum:faceNum]
	faceInfo.FaceOrient = (*[10]int32)(unsafe.Pointer(asfFaceInfo.faceOrient))[:faceNum:faceNum]
	if asfFaceInfo.faceID != nil {
		faceInfo.FaceID = (*[10]int32)(unsafe.Pointer(asfFaceInfo.faceID))[:faceNum:faceNum]
	}
	// 新增参数 人脸信息
	faceInfo.FaceDataInfoList = (*[10]C.ASF_FaceDataInfo)(unsafe.Pointer(asfFaceInfo.faceDataInfoList))[:faceNum:faceNum]
	faceInfo.WearGlasses = (*[10]float32)(unsafe.Pointer(asfFaceInfo.wearGlasses))[:faceNum:faceNum]
	faceInfo.LeftEyeClosed = (*[10]int32)(unsafe.Pointer(asfFaceInfo.leftEyeClosed))[:faceNum:faceNum]
	faceInfo.RightEyeClosed = (*[10]int32)(unsafe.Pointer(asfFaceInfo.rightEyeClosed))[:faceNum:faceNum]

	faceInfo.FaceNum = faceNum
	faceInfo.native = asfFaceInfo
	return
}

/******************************************************
* 图像质量检测，（RGB模式： 识别阈值：0.49 注册阈值：0.63  口罩模式：识别阈值：0.29）
* 图像数据以结构体形式传入，对采用更高字节对齐方式的图像兼容性更好
******************************************************/
func (engine *FaceEngine) ASFImageQualityDetectPro(width, height int, format C.MInt32, imgData []byte, single SingleFaceInfo, isMask int) (float32, error) {
	var confidenceLevel float32 = 0
	asfSingleFaceInfo := &C.ASF_SingleFaceInfo{
		C.MRECT{
			C.MInt32(single.FaceRect.Left),
			C.MInt32(single.FaceRect.Top),
			C.MInt32(single.FaceRect.Right),
			C.MInt32(single.FaceRect.Bottom)},
		C.MInt32(single.FaceOrient),
		C.ASF_FaceDataInfo(single.DataInfo),
	}
	r := C.ASFImageQualityDetect(engine.handle,
		C.MInt32(width),
		C.MInt32(height),
		format,
		(*C.MUInt8)(unsafe.Pointer(&imgData[0])),
		asfSingleFaceInfo,
		C.MInt32(isMask),
		(*C.MFloat)(unsafe.Pointer(&confidenceLevel)),
		C.ASF_DETECT_MODEL_RGB,
	)
	if r != C.MOK {
		return 0, newError(int(r), "图像质量检测失败")
	}
	return confidenceLevel, nil
}

// 年龄/性别/人脸3D角度（该接口仅支持RGB图像），最多支持4张人脸信息检测，超过部分返回未知
// RGB活体仅支持单人脸检测，该接口不支持检测IR活体
func (engine *FaceEngine) ProcessPro(width, height int, format C.MInt32, imgData []byte, detectedFaces MultiFaceInfo, combinedMask C.MInt32) error {
	r := C.ASFProcess(engine.handle,
		C.MInt32(width),
		C.MInt32(height),
		format,
		(*C.MUInt8)(unsafe.Pointer(&imgData[0])),
		detectedFaces.native,
		combinedMask)
	if r != C.MOK {
		return newError(int(r), "检测人脸信息Process失败")
	}
	return nil
}

// 该接口目前仅支持单人脸IR活体检测（不支持年龄、性别、3D角度的检测），默认取第一张人脸
func (engine *FaceEngine) ProcessIRPro(width, height int, format C.MInt32, imgData []byte, detectedFaces MultiFaceInfo, combinedMask C.MInt32) error {
	r := C.ASFProcess(engine.handle,
		C.MInt32(width),
		C.MInt32(height),
		format,
		(*C.MUInt8)(unsafe.Pointer(&imgData[0])),
		detectedFaces.native,
		combinedMask)
	if r != C.MOK {
		return newError(int(r), "检测人脸IR活体信息失败")
	}
	return nil
}

// 设置活体置信度
// 取值范围[0-1]内部默认数值RGB-0.5，IR-0.7， 用户可以根据实际需求，设置不同的阈值
func (engine *FaceEngine) SetLivenessParamPro(threshold LivenessThreshold) error {
	asfLivenessThreshold := &C.ASF_LivenessThreshold{
		thresholdmodel_BGR: C.MFloat(threshold.ThresholdModelBGR),
		thresholdmodel_IR:  C.MFloat(threshold.ThresholdModelIR),
	}
	r := C.ASFSetLivenessParam(engine.handle, asfLivenessThreshold)
	if r != C.MOK {
		return newError(int(r), "设置活体置信度失败")
	}
	return nil
}

// 设置遮挡范围
func (engine *FaceEngine) SetFaceShelterParamPro(threshold float32) error {
	shelterThreshold := C.MFloat(threshold)
	r := C.ASFSetFaceShelterParam(engine.handle, shelterThreshold)
	if r != C.MOK {
		return newError(int(r), "设置遮挡范围失败")
	}
	return nil
}

// 获取版本信息
func (engine *FaceEngine) GetVersionPro() Version {
	info := C.ASFGetVersion()
	return Version{
		Version:   C.GoString(info.Version),
		BuildDate: C.GoString(info.BuildDate),
		CopyRight: C.GoString(info.CopyRight),
	}
}

// 将 特征值转 []byte 为 FaceFeature 结构体
func ConvertToFaceFeaturePro(byteArr []byte) (faceFeature FaceFeature) {
	length := len(byteArr)
	nav := &C.ASF_FaceFeature{}
	nav.featureSize = C.MInt32(length)

	arr := (*C.MByte)(C.malloc(C.size_t(length)))
	// 首地址
	faceFeature.featurePtr = arr
	ps := (*[1 << 28]C.MByte)(unsafe.Pointer(arr))[:length:length]
	for i := 0; i < len(ps); i++ {
		ps[i] = C.MByte(byteArr[i])
	}
	nav.feature = arr

	faceFeature.Feature = byteArr
	faceFeature.FeatureSize = int32(length)
	faceFeature.native = nav
	return faceFeature
}

// 单人脸特征提取
func (engine *FaceEngine) FaceFeatureExtractPro(width, height int, format C.MInt32, imgData []byte, faceInfo SingleFaceInfo, registerOrNot int, mask uint32) (faceFeature FaceFeature, err error) {
	asfFaceFeature := &C.ASF_FaceFeature{}
	asfFaceInfo := &C.ASF_SingleFaceInfo{
		C.MRECT{
			C.MInt32(faceInfo.FaceRect.Left),
			C.MInt32(faceInfo.FaceRect.Top),
			C.MInt32(faceInfo.FaceRect.Right),
			C.MInt32(faceInfo.FaceRect.Bottom),
		},
		C.MInt32(faceInfo.FaceOrient),
		faceInfo.DataInfo,
	}
	r := C.ASFFaceFeatureExtract(
		engine.handle,
		C.MInt32(width),
		C.MInt32(height),
		format,
		(*C.MUInt8)(unsafe.Pointer(&imgData[0])),
		asfFaceInfo,
		func(a int) uint32 {
			if a == 1 {
				return ASFRegister
			} else {
				return ASFRecognition
			}
		}(registerOrNot),
		C.MInt32(mask),
		asfFaceFeature,
	)
	if r != C.MOK {
		return FaceFeature{}, newError(int(r), "提取人脸特征失败")
	}
	length := int32(asfFaceFeature.featureSize)
	faceFeature.FeatureSize = length
	faceFeature.Feature = make([]byte, length)
	byteArr := (*[1 << 28]byte)(unsafe.Pointer(asfFaceFeature.feature))[:length:length]
	arr := (*C.MByte)(C.malloc(C.size_t(int32(asfFaceFeature.featureSize))))
	faceFeature.featurePtr = arr
	ps := (*[1 << 28]C.MByte)(unsafe.Pointer(arr))[:length:length]
	for i := 0; i < len(ps); i++ {
		ps[i] = C.MByte(byteArr[i])
		faceFeature.Feature[i] = byteArr[i]
	}
	asfFaceFeature.feature = arr
	faceFeature.native = asfFaceFeature
	return faceFeature, err
}

// 人脸特征比对
func (engine *FaceEngine) FaceFeatureComparePro(feature1, feature2 FaceFeature, compareModel int32) (float32, error) {
	var confidenceLevel float32 = 0

	r := C.ASFFaceFeatureCompare(engine.handle,
		feature1.native,
		feature2.native,
		(*C.MFloat)(unsafe.Pointer(&confidenceLevel)),
		func(a int32) uint32 {
			if compareModel == 1 {
				return ASFLifePhoto
			} else {
				return ASFIdPhoto
			}
		}(compareModel),
	)
	if r != C.MOK {
		return 0, newError(int(r), "人脸特征比对失败!")
	}

	return confidenceLevel, nil
}

// 获取年龄信息
func (engine *FaceEngine) GetAgePro() (AgeInfo, error) {
	asfAgeInfo := &C.ASF_AgeInfo{}
	r := C.ASFGetAge((C.MHandle)(engine.handle), asfAgeInfo)
	if r != C.MOK {
		return AgeInfo{}, newError(int(r), "获取年龄信息失败")
	}
	num := int32(asfAgeInfo.num)
	return AgeInfo{
		AgeArray: (*[10]int32)(unsafe.Pointer(asfAgeInfo.ageArray))[:num:num],
		Num:      num,
	}, nil
}

// 获取性别信息
func (engine *FaceEngine) GetGenderPro() (GenderInfo, error) {
	asfGenderInfo := &C.ASF_GenderInfo{}
	r := C.ASFGetGender((C.MHandle)(engine.handle), asfGenderInfo)
	if r != C.MOK {
		return GenderInfo{}, newError(int(r), "获取性别信息失败")
	}
	num := int32(asfGenderInfo.num)
	return GenderInfo{
		GenderArray: (*[10]int32)(unsafe.Pointer(asfGenderInfo.genderArray))[:num:num],
		Num:         num,
	}, nil
}

// 获取3D角度信息
// GetFace3DAngle 获取3D角度信息
func (engine *FaceEngine) GetFace3DAnglePro() (Face3DAngle, error) {
	asfFace3DAngle := &C.ASF_Face3DAngle{}
	r := C.ASFGetFace3DAngle((C.MHandle)(engine.handle), asfFace3DAngle)
	if r != C.MOK {
		return Face3DAngle{}, newError(int(r), "获取3D角度信息失败")
	}
	num := int32(asfFace3DAngle.num)
	return Face3DAngle{
		Roll:  (*[10]float32)(unsafe.Pointer(asfFace3DAngle.roll))[:num:num],
		Yaw:   (*[10]float32)(unsafe.Pointer(asfFace3DAngle.yaw))[:num:num],
		Pitch: (*[10]float32)(unsafe.Pointer(asfFace3DAngle.pitch))[:num:num],
		//Status: (*[10]int32)(unsafe.Pointer(asfFace3DAngle.status))[:num:num],
		Num: int32(asfFace3DAngle.num),
	}, nil
}

// 获取RGB活体结果
func (engine *FaceEngine) GetLivenessScorePro() (LivenessInfo, error) {
	asfLivenessInfo := &C.ASF_LivenessInfo{}
	r := C.ASFGetLivenessScore((C.MHandle)(engine.handle), asfLivenessInfo)
	if r != C.MOK {
		return LivenessInfo{}, newError(int(r), "获取活体信息失败")
	}
	num := int32(asfLivenessInfo.num)
	return LivenessInfo{
		IsLive: (*[10]int32)(unsafe.Pointer(asfLivenessInfo.isLive))[:num:num],
		Num:    num,
	}, nil
}

// 获取IR活体结果
func (engine *FaceEngine) GetLivenessScoreIRPro() (LivenessInfo, error) {
	asfLivenessInfo := &C.ASF_LivenessInfo{}
	r := C.ASFGetLivenessScore_IR((C.MHandle)(engine.handle), asfLivenessInfo)
	if r != C.MOK {
		return LivenessInfo{}, newError(int(r), "获取活体信息失败")
	}
	num := int32(asfLivenessInfo.num)
	return LivenessInfo{
		IsLive: (*[10]int32)(unsafe.Pointer(asfLivenessInfo.isLive))[:num:num],
		Num:    num,
	}, nil
}

// 获取口罩检测的结果
func (engine *FaceEngine) GetMaskPro() (maskInfo MaskInfo, err error) {
	asfMaskInfo := &C.ASF_MaskInfo{}
	r := C.ASFGetMask(engine.handle, (*C.ASF_MaskInfo)(unsafe.Pointer(asfMaskInfo)))
	if r != C.MOK {
		return maskInfo, newError(int(r), "获取口罩信息失败")
	}
	num := int32(asfMaskInfo.num)
	return MaskInfo{
		MaskArray: (*[10]int32)(unsafe.Pointer(asfMaskInfo.maskArray))[:num:num],
		Num:       num,
	}, nil
}

// 获取额头区域位置
func (engine *FaceEngine) GetFaceLandMarkInfo() (landMarkInfo LandMarkInfo, err error) {
	asfLandMarkInfo := &C.ASF_LandMarkInfo{}
	r := C.ASFGetFaceLandMark(engine.handle, asfLandMarkInfo)
	if r != C.MOK {
		return landMarkInfo, newError(int(r), "获取额头区域位置失败")
	}
	num := int32(asfLandMarkInfo.num)
	asfPoint := (*[10]C.ASF_FaceLandmark)(unsafe.Pointer(asfLandMarkInfo.point))[:num:num]
	point := make([]FaceLandMark, num)
	for i := int32(0); i < num; i++ {
		point[i] = FaceLandMark{
			X: float32(asfPoint[i].x),
			Y: float32(asfPoint[i].y),
		}
	}
	return LandMarkInfo{
		Point: point,
		Num:   num,
	}, nil
}

// 销毁引擎
func (engine *FaceEngine) DestroyPro() error {
	r := C.ASFUninitEngine(engine.handle)
	if r != C.MOK {
		return newError(int(r), "销毁引擎失败")
	}
	return nil
}

// 从多人脸结构体中提取单人脸信息
func GetSingleFaceInfo(multiFaceInfo MultiFaceInfo) (faceInfo []SingleFaceInfo) {
	faceInfo = make([]SingleFaceInfo, multiFaceInfo.FaceNum)
	for i := 0; i < len(faceInfo); i++ {
		faceInfo[i].FaceRect = Rect{
			Left:   multiFaceInfo.FaceRect[i].Left,
			Top:    multiFaceInfo.FaceRect[i].Top,
			Right:  multiFaceInfo.FaceRect[i].Right,
			Bottom: multiFaceInfo.FaceRect[i].Bottom,
		}
		faceInfo[i].FaceOrient = multiFaceInfo.FaceOrient[i]
	}
	return
}

// 释放内存
func (feature *FaceFeature) Release() {
	if feature.featurePtr != nil {
		C.free(unsafe.Pointer(feature.featurePtr))
	}
}

// 实现Error接口
func (err EngineError) Error() string {
	info, _ := json.Marshal(err.Text)
	return string(info)
}

func newError(code int, text string) EngineError {
	return EngineError{
		Code: code,
		Text: text,
	}
}
